﻿using System;
using static CyberU;
using static CyberU.UI;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using Newtonsoft.Json;
using UnityEngine.Serialization;

public class GraphEdge : ConnectLine
{
    public SimpleText _title;

    public SimpleText title
    {
        get
        {
            if (_title == null)
            {
                _title = FindComponentInChildren<SimpleText>(gameObject);
            }

            return _title;
        }
        set { _title = value; }
    }

    public SimpleText content;

    void Awake()
    {
        title = GetOrAddComponent<SimpleText>(GetGameObject("Title", gameObject));
        content = GetOrAddComponent<SimpleText>(GetGameObject("Content", gameObject));
            edgeCollider = GetOrAddComponent<EdgeCollider2D>(gameObject);
            edgeCollider.isTrigger = true;
            rigidBody= GetOrAddComponent<Rigidbody2D>(gameObject);
            rigidBody.isKinematic = true;
            rigidBody.bodyType = RigidbodyType2D.Kinematic;
    }

    public Rigidbody2D rigidBody;
    public GraphEdgeData _data;

    public GraphEdgeData data
    {
        get { return _data; }
        set
        {
            _data = value;
            UpdateData(value);
        }
    }

    public static void UpdateData(GraphEdgeData data)
    {
    }

    private void Update()
    {
        base.OnUpdate();
        UpdateTextPosition();
        UpdateEdgeCollider();
    }

    public void UpdateEdgeCollider()
    {
        if (edgeCollider != null)
        {
            Vector2[] points = new Vector2[]
            {
                rigidbodyStart.position,
                rigidbodyEnd.position
            };
    
            edgeCollider.points = points;
        }

    }

    public void UpdateTextPosition()
    {
        // Delog($"{title} {content}");
        if (title != null && content != null && start != null && end != null)
        {
            Vector3 worldMiddle = middlePosition;
            Vector2 screenPos = Camera.main.WorldToScreenPoint(worldMiddle);
            RectTransform canvasRect = graph.canvas.GetComponent<RectTransform>();
            Vector2 localPos;
            RectTransformUtility.ScreenPointToLocalPointInRectangle(
                canvasRect,
                screenPos,
                graph.canvas.worldCamera,
                out localPos
            );
            title.rectTransform.anchoredPosition = new Vector2(localPos.x, localPos.y + title.fontSize / 2f);
            content.rectTransform.anchoredPosition = new Vector2(localPos.x, localPos.y - content.fontSize / 2f);
            title.rectTransform.rotation = Quaternion.Euler(0, 0, angle);
            content.rectTransform.rotation = Quaternion.Euler(0, 0, angle);
        }
    }

    public Graph graph;
    public float damper;
    public float springForce;
    public float targetDistance;

    public Rigidbody2D rigidbodyStart;
    public Rigidbody2D rigidbodyEnd;
    public EdgeCollider2D edgeCollider;

    public void Initial(GraphEdgeData data_, GameObject start, GameObject end)
    {
        data = data_;
        data_.edge = this;
        base.Initial(start: start, end: end);
        rigidbodyStart = GetOrAddComponent<Rigidbody2D>(start);
        rigidbodyEnd = GetOrAddComponent<Rigidbody2D>(end);
    }

    void FixedUpdate()
    {
        if (rigidbodyStart == null || rigidbodyEnd == null) return;
        Vector2 direction = rigidbodyEnd.position - rigidbodyStart.position;
        float currentDistance = direction.magnitude;
        float displacement = currentDistance - targetDistance;
        Vector2 springForceVector = springForce * displacement * direction.normalized;
        Vector2 relativeVelocity = rigidbodyEnd.velocity - rigidbodyStart.velocity;
        Vector2 dampingForceVector = damper * relativeVelocity;
        // Vector2 totalForce = springForceVector - dampingForceVector;
        Vector2 totalForce = springForceVector;
        // if (data.fromId == "node_002")
        // {
        // Delog($"{(currentDistance,targetDistance,displacement)}");
        // }
        rigidbodyStart.AddForce(totalForce);
        rigidbodyEnd.AddForce(-totalForce);
    }

    [JsonIgnore]
    public GraphNode to
    {
        get { return AsComponent<GraphNode>(end); }
    }

    [JsonIgnore]
    public GraphNode from
    {
        get { return AsComponent<GraphNode>(start); }
    }
}

public class GraphEdgeData
{
    [Newtonsoft.Json.JsonIgnore]
    public string _fromId;

    public string fromId
    {
        get
        {
            if (edge==null||edge.from == null)
            {
                return _fromId;
            }

            _fromId = edge.from.data.id;
            return _fromId;
        }
        set{_fromId = value;}
    }

    [Newtonsoft.Json.JsonIgnore]
    public string _toId;
    public string toId
    {
        get
        {
            if (edge==null||edge.to == null)
            {
                return _toId;
            }
            _toId = edge.to.data.id;
            return _toId;
        }
        set{_toId = value;}
    }

    public GraphEdge edge;

    public GraphEdgeData()
    {
    }

    public GraphEdgeData(GraphEdge edge)
    {
        this.edge = edge;
    }
    //
}